package util;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SpringLayout;
import javax.swing.UIManager;

public class ErrorMessage{

	public final static int CRITICAL_ERROR = 1;
	public final static int WARNING_ERROR = 2;
	
	private static ErrorMessage _instance = null;
	private SimpleErrorMsg simpleMsgFr;
	private ComplexErrorMsg complexMsgFr;
	private Icon errorIcon, warningIcon;
	
	private ErrorMessage()
	{
		// Get error icon and warning icon of JOPtionPane
		errorIcon = UIManager.getIcon("OptionPane.errorIcon");		
		warningIcon = UIManager.getIcon("OptionPane.warningIcon");
		
		simpleMsgFr = new SimpleErrorMsg();
		complexMsgFr = new ComplexErrorMsg();
	}
	
	public static void displayError(int errorLevel, boolean threaded, String errorTitle, String errorBody)
	{
		if(_instance == null)
			_instance = new ErrorMessage();
		
		if(threaded)
			_instance.dspSimpleThreaded(errorLevel, errorTitle, errorBody);
		else
			_instance.dspSimpleError(errorLevel, errorTitle, errorBody);
	}
	
	private void dspSimpleError(int errorLevel, String errorTitle, String errorBody)
	{
		simpleMsgFr.messageTitle.setText(errorTitle);
		// simpleMsgFr.messageBody.setText(errorBody);
		simpleMsgFr.setMessageBody(errorBody);
		switch(errorLevel)
		{
		case CRITICAL_ERROR:
			simpleMsgFr.messageIcon.setIcon(errorIcon);
			simpleMsgFr.setTitle("Critical Error");
			break;
		case WARNING_ERROR:
			simpleMsgFr.messageIcon.setIcon(warningIcon);
			simpleMsgFr.setTitle("Warning");
			break;
		}
		
		simpleMsgFr.setVisible(true);
	}
	
	private void dspSimpleThreaded(int errorLevel, String errorTitle, String errorBody)
	{
		final int errorLevel2 = errorLevel;
		final String errorTitle2 = errorTitle;
		final String errorBody2 = errorBody;
		
		new Thread()
		{
			public void run()
			{
				dspSimpleError(errorLevel2, errorTitle2, errorBody2);
			}
		}.start();
	}
	
	public static void displayError(int errorLevel, boolean threaded, String errorTitle, String errorBody, List<String> errorList)
	{
		if(_instance == null)
			_instance = new ErrorMessage();
		
		if(threaded)
			_instance.dspComplexThreaded(errorLevel, errorTitle, errorBody, errorList);
		else
			_instance.dspComplexError(errorLevel, errorTitle, errorBody, errorList);
	}
	
	private void dspComplexError(int errorLevel, String errorTitle, String errorBody, List<String> errorList)
	{
		complexMsgFr.messageTitle.setText(errorTitle);
		complexMsgFr.messageBody.setText(errorBody);
		
		complexMsgFr.messageList.setText("");
		for(String errMsg: errorList)
			complexMsgFr.messageList.append(errMsg+"\n\n");
				
		complexMsgFr.msgListSP.updateUI();		
				
		switch(errorLevel)
		{
		case CRITICAL_ERROR:
			complexMsgFr.messageIcon.setIcon(errorIcon);
			complexMsgFr.setTitle("Critical Error");
			break;
		case WARNING_ERROR:
			complexMsgFr.messageIcon.setIcon(warningIcon);
			complexMsgFr.setTitle("Warning");
			break;
		}
		
		complexMsgFr.setVisible(true);		
	}

	private void dspComplexThreaded(int errorLevel, String errorTitle, String errorBody, List<String> errorList)
	{
		final int errorLevel2 = errorLevel;
		final String errorTitle2 = errorTitle;
		final String errorBody2 = errorBody;
		final List<String> errorList2 = errorList;
		
		new Thread()
		{
			public void run()
			{
				dspComplexError(errorLevel2, errorTitle2, errorBody2, errorList2);
			}
		}.start();
	}
	
	private class SimpleErrorMsg extends JFrame implements ActionListener
	{
		private static final long serialVersionUID = 1L;
		JLabel messageTitle, messageIcon;
		JTextArea messageBody;
		JButton okBtn;
		
		public SimpleErrorMsg()
		{
			messageTitle = new JLabel();
			Font f = new Font("sanserif", Font.BOLD, 14);
			messageTitle.setFont(f);
			
			messageBody = new JTextArea();
			messageBody.setBackground(messageTitle.getBackground());
			messageBody.setForeground(messageTitle.getForeground());
			f = new Font("sanserif", Font.PLAIN, 13);
			messageBody.setFont(f);
			messageBody.setEditable(false);
			messageBody.setLineWrap(true);
			messageBody.setWrapStyleWord(true);
			
			messageBody.setSize(370, 200);
			
			messageIcon = new JLabel();
			messageIcon.setSize(20, 20);
			
			okBtn = new JButton("OK");
			f = new Font("sanserif", Font.BOLD, 14);
			okBtn.setFont(f);
			okBtn.addActionListener(this);
			
			SpringLayout spring = new SpringLayout();
			
			Container cp = this.getContentPane();
			cp.setLayout(spring);
			cp.add(messageTitle);
			cp.add(messageBody);
			cp.add(messageIcon);
			cp.add(okBtn);
			
			spring.putConstraint(SpringLayout.WEST, messageIcon, 15, SpringLayout.WEST, cp);
			spring.putConstraint(SpringLayout.NORTH, messageIcon, 25, SpringLayout.NORTH, cp);
			
			spring.putConstraint(SpringLayout.WEST, messageTitle, 15, SpringLayout.EAST, messageIcon);
			spring.putConstraint(SpringLayout.NORTH, messageTitle, 20, SpringLayout.NORTH, cp);
			
			spring.putConstraint(SpringLayout.WEST, messageBody, 15, SpringLayout.EAST, messageIcon);
			spring.putConstraint(SpringLayout.NORTH, messageBody, 5, SpringLayout.SOUTH, messageTitle);
			spring.putConstraint(SpringLayout.EAST, messageBody, -15, SpringLayout.EAST, cp);
			spring.putConstraint(SpringLayout.SOUTH, messageBody, -65, SpringLayout.SOUTH, cp);
			
			spring.putConstraint(SpringLayout.EAST, okBtn, -60, SpringLayout.EAST, cp);
			spring.putConstraint(SpringLayout.SOUTH, okBtn, -20, SpringLayout.SOUTH, cp);
			
			this.setSize(500, 200);
			this.setLocation(300, 300);
			this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);			
		}

		@Override
		public void actionPerformed(ActionEvent e) {			
			if(e.getSource().equals(okBtn))
			{
				this.setVisible(false);
			}
		}
		
		public void setMessageBody(String errorBody)
		{
			messageBody.setText(errorBody);
			
			// Adjust '20' according to the Font height.
			messageBody.setSize(370, (errorBody.length()/55+2)*20+50);
			messageBody.repaint();
			messageBody.validate();
		
			this.setSize(450, messageBody.getHeight()+100);
			this.repaint();		
			this.validate();
		}
	}
	
	private class ComplexErrorMsg extends JFrame implements ActionListener
	{
		private static final long serialVersionUID = 1L;
		JLabel messageTitle, messageIcon;
		JTextArea messageBody, messageList;
		JScrollPane msgListSP;
		JButton okBtn;
		
		public ComplexErrorMsg()
		{
			messageTitle = new JLabel();
			Font f = new Font("sanserif", Font.BOLD, 14);
			messageTitle.setFont(f);
			
			messageBody = new JTextArea();
			messageBody.setBackground(messageTitle.getBackground());
			messageBody.setForeground(messageTitle.getForeground());
			f = new Font("sanserif", Font.PLAIN, 13);
			messageBody.setFont(f);
			messageBody.setEditable(false);
			messageBody.setLineWrap(true);
			messageBody.setWrapStyleWord(true);
			messageBody.setSize(550, 150);
			
			messageList = new JTextArea();
			messageList.setEditable(false);
			messageList.setLineWrap(true);
			messageList.setWrapStyleWord(true);
			messageList.setAutoscrolls(true);
			messageList.setMargin(new Insets(5,5,5,5));
			msgListSP = new JScrollPane();
			msgListSP.setViewportView(messageList);
			msgListSP.setPreferredSize(new Dimension(530, 270));			
			
			messageIcon = new JLabel();
			messageIcon.setSize(50, 50);
			
			okBtn = new JButton("OK");
			f = new Font("sanserif", Font.BOLD, 14);
			okBtn.setFont(f);
			okBtn.addActionListener(this);
			
			SpringLayout spring = new SpringLayout();
			
			Container cp = this.getContentPane();
			cp.setLayout(spring);
			cp.add(messageTitle);
			cp.add(messageBody);
			cp.add(messageIcon);
			cp.add(msgListSP);
			cp.add(okBtn);
			
			spring.putConstraint(SpringLayout.WEST, messageIcon, 15, SpringLayout.WEST, cp);
			spring.putConstraint(SpringLayout.NORTH, messageIcon, 25, SpringLayout.NORTH, cp);
			
			spring.putConstraint(SpringLayout.WEST, messageTitle, 15, SpringLayout.EAST, messageIcon);
			spring.putConstraint(SpringLayout.NORTH, messageTitle, 20, SpringLayout.NORTH, cp);
			
			spring.putConstraint(SpringLayout.WEST, messageBody, 15, SpringLayout.EAST, messageIcon);
			spring.putConstraint(SpringLayout.NORTH, messageBody, 5, SpringLayout.SOUTH, messageTitle);
			
			spring.putConstraint(SpringLayout.WEST, msgListSP, 15, SpringLayout.EAST, messageIcon);
			spring.putConstraint(SpringLayout.NORTH, msgListSP, 15, SpringLayout.SOUTH, messageBody);
						
			spring.putConstraint(SpringLayout.EAST, okBtn, -60, SpringLayout.EAST, cp);
			spring.putConstraint(SpringLayout.SOUTH, okBtn, -20, SpringLayout.SOUTH, cp);
			
			this.setSize(650, 450);
			this.setLocation(200, 200);
			this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);	
		}
		
		public void actionPerformed(ActionEvent e) {
			if(e.getSource().equals(okBtn))
			{
				this.setVisible(false);
			}			
		}		
	}

	
/*	
	public static void main(String[] args) {
	//	simpleErrorMessage(2, "Testing error", "This is a testing for displaying error message.");
		List<String> errMsg01 = new ArrayList<String>();
		errMsg01.add("An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.");
		errMsg01.add("Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs of elements e1 and e2 such that e1.equals(e2), and they typically allow multiple null elements if they allow null elements at all.");
		errMsg01.add("It is not inconceivable that someone might wish to implement a list that prohibits duplicates, by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.");
		errMsg01.add("The List interface places additional stipulations, beyond those specified in the Collection interface, on the contracts of the iterator, add, remove, equals, and hashCode methods.");
		errMsg01.add("Declarations for other inherited methods are also included here for convenience.");
		errMsg01.add("An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.");
		errMsg01.add("Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs of elements e1 and e2 such that e1.equals(e2), and they typically allow multiple null elements if they allow null elements at all.");
		
		String errMsg02 = "This is to test a longer error message.";
		errMsg02+=" This message will not end that fast.";
		errMsg02+=" Believe me anot, there is still long way.";
//		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";
//		errMsg02+=" Now this is the end. Farewell";		
		errMsg02+=" Believe me anot, there is still long way.";
//		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";

		ErrorMessage.displayError(WARNING_ERROR, false, "Testing error", errMsg02);
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		errMsg02+=" Believe me anot, there is still long way.";
		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";
//		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";
//		errMsg02+=" Believe me anot, there is still long way.";
		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" Now this is the end. Farewell";
		errMsg02+=" Even at now this is not the end yet.";

		ErrorMessage.displayError(WARNING_ERROR, false, "Testing error", errMsg02);
		
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		errMsg02+=" Believe me anot, there is still long way.";
		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";
//		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" And wish you a merry Xmas and Happy New Year 2012";
		errMsg02+=" Believe me anot, there is still long way.";
//		errMsg02+=" Even at now this is not the end yet.";
		errMsg02+=" Now this is the end. Farewell";
//		errMsg02+=" Even at now this is not the end yet.";

		ErrorMessage.displayError(WARNING_ERROR, false, "Testing error", errMsg02);
		
	}
*/
}
